package cn.swanit.common.base.handler;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.swanit.common.base.Result;
import cn.swanit.common.base.exception.IotCloudException;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public Result onException(MaxUploadSizeExceededException e) {
        return Result.error("上传文件过大");
    }

    // 处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常，详情继续往下看代码
    @ExceptionHandler(BindException.class)
    public Result onException(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream().map(n -> n.getField() + ":" + n.getDefaultMessage()).collect(Collectors.joining(";"));
        log.error("==BindException=={}", message);
        return Result.error("参数绑定异常", message);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public Result onException(ConstraintViolationException e) {
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage)
                .collect(Collectors.joining());
        log.error("==ConstraintViolationException=={}", message);
        return Result.error("入参异常", message);
    }

    // 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result onException(MethodArgumentNotValidException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream().map(n -> n.getField() + ":" + n.getDefaultMessage()).collect(Collectors.joining(";"));
        log.error("==MethodArgumentNotValidException=={}", message);
        return Result.error("入参异常", message);
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result onException(HttpRequestMethodNotSupportedException e) {
        log.error("==HttpRequestMethodNotSupportedException=={}", e.getMessage());
        return Result.error("请求方法【" + e.getMethod() + "】类型错误");
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public Result onException(HttpMediaTypeNotSupportedException e) {
        log.error("==HttpMediaTypeNotSupportedException=={}", e.getMessage());
        return Result.error("MediaType类型【" + e.getContentType() + "】类型错误");
    }

    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public Result onException(SQLIntegrityConstraintViolationException e) {
        String message = e.getMessage();
        log.error("==SQLIntegrityConstraintViolationException=={}", message);
        return Result.error("Duplicate Key", message);
    }

    @ExceptionHandler(NullPointerException.class)
    public Result onNullPointerException(NullPointerException e) {
        e.printStackTrace();
        String message = e.getMessage();
        log.error("==NullPointerException=={}==class=={}", message, e.getClass());
        return Result.error("系统发生空指针异常", message);
    }

    @ExceptionHandler(BlockException.class)
    public Result onBlockException(BlockException e) {
        String msg = "请求过于频繁";
        if (e instanceof FlowException) {
            msg = "限流了";
        } else if (e instanceof DegradeException) {
            msg = "降级了";
        } else if (e instanceof ParamFlowException) {
            msg = "热点参数限流";
        } else if (e instanceof SystemBlockException) {
            msg = "系统规则（负载/...不满足要求）";
        } else if (e instanceof AuthorityException) {
            msg = "授权规则不通过";
        }
        e.printStackTrace();
        String message = e.getMessage();
        log.error("==BlockException=={}==class=={}", message, e.getClass());
        return Result.error(msg);
    }

    @ExceptionHandler(NotLoginException.class)
    public Result onNotLoginException(NotLoginException e) {
        e.printStackTrace();
        String message = e.getMessage();
        log.error("==NotLoginException=={}====", message);
        // 判断场景值，定制化异常信息
        switch (e.getType()) {
            case NotLoginException.NOT_TOKEN:
                message = "未提供token";
                break;
            case NotLoginException.INVALID_TOKEN:
                message = "token无效";
                break;
            case NotLoginException.TOKEN_TIMEOUT:
                message = "token已过期";
                break;
            case NotLoginException.BE_REPLACED:
                message = "token已被顶下线";
                break;
            case NotLoginException.KICK_OUT:
                message = "token已被踢下线";
                break;
            default:
                message = "当前会话未登录";
                break;
        }
        return Result.error("NotLoginException", message);
    }

    @ExceptionHandler(NotPermissionException.class)
    public Result onNotPermissionException(NotPermissionException e) {
        e.printStackTrace();
        String message = e.getMessage();
        log.error("==NotPermissionException=={}====", message);
        return Result.error("NotPermissionException", message);
    }

    @ExceptionHandler(NotRoleException.class)
    public Result onNotRoleException(NotRoleException e) {
        e.printStackTrace();
        String message = e.getMessage();
        log.error("==NotRoleException=={}====", message);
        return Result.error("NotRoleException", message);
    }

    @ExceptionHandler(IotCloudException.class)
    public Result onSsyCloudException(IotCloudException e) {
        e.printStackTrace();
        String message = e.getMessage();
        log.error("==ServiceException=={}==class=={}", message, e.getClass());
        return new Result(e.getCode(), e.getMessage(), null);
    }

    @ExceptionHandler(Exception.class)
    public Result onException(Exception e) {
        e.printStackTrace();
        String message = e.getMessage();
        log.error("==Exception=={}====", message);
        return Result.error("系统发生异常", message);
    }
}
